home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 12 / BBS in a box XII-2.iso / Files II / Prog / D-G / GrafSys2.0rel.sit / GrafSys 2.0 rel / GrafSys 2.0 source / GrafSysObject.p < prev    next >
Encoding:
Text File  |  1993-07-21  |  24.9 KB  |  787 lines  |  [TEXT/PJMM]

  1. unit GrafSysObject;
  2.  
  3. interface
  4.     uses
  5.         Matrix, Transformations, OffscreenCore, GrafSysCore, GrafSysScreen;
  6.  
  7.     const
  8.         MaxLine = 8000;
  9.  
  10.     type
  11.  
  12.         LineEntry = record
  13.                 fromP, toP: longint; (* max 8000 lines per model supported in this incarnation.  *)
  14.                 hs, vs, he, ve: integer; (* for fast drawing. buffers transformed locations *)
  15.                 newline: boolean; (* for optimization. if true, no MoveTo required *)
  16.                 newLineColor: boolean;
  17.                 LineColor: RGBColor;
  18.             end;
  19.  
  20.         LineBufPtr = ^LineBufRec;
  21.         LineBufRec = array[1..MaxLine] of LineEntry;
  22.  
  23.         TSObject3D = object(TSGenericObject3D)
  24.                 Lines: LineBufPtr;
  25.                 numLines: integer;
  26.                 AutoErase: Boolean;
  27.                 UseBounds: Boolean;
  28.                 procedure Init;
  29.                 override;
  30.                 function Clone: TGenericObject;    {also clone line description buffer}
  31.                 override;
  32.                 procedure Reset;
  33.                 override;
  34.                 procedure Kill;
  35.                 override;
  36.                 function AddLine (fIndex, tIndex: longint): integer;        {add line to objects database. returns line index or -1}
  37.                 function ChangeLine (LineIndex, fIndex, tIndex: longint): boolean;    {change line description of line with index }
  38.                                                                                     {lineIndex. True if successful                }
  39.                 function ChangeLineColor (LineIndex: longint; theColor: RGBColor): boolean;
  40.                                                                         {change the color from this line on for all following }
  41.                                                                         {until the next ChangeColor command                      }
  42.                 function GetLineColor (LineIndex: longint; var theColor: RGBColor; var ChangeHere: boolean): Boolean;
  43.                                                                         {returns the currently active color of specified line}
  44.                 function KeepLineColor (LineIndex: longint): boolean;    {deletes change linecolor information. This line and }
  45.                                                                         {all following will have the same color as the pre-  }
  46.                                                                         {vious                                                      }
  47.                 function DeleteLine (LineIndex: integer): Boolean;        {delete whole line from model. True on success}
  48.                 function DeletePoint (index: longint): boolean;            {override inherited proc of this kind. This one checks}
  49.                 override;                                                        {first if point is referenced to by a point. If so, it }
  50.                                                                         {returns false and doesn't delete the point            }
  51.                 procedure GetLine (lineIndex: integer; var src, tgt: LongInt); {returns start and endpoint of line}
  52.                 procedure BuildNewLines;    {should not be called from the outside}
  53.                 procedure CollectLineData; {internal use only. fill the screen vals from point definition into line array}
  54.                 procedure SetAutoerase (TurnOn: Boolean);                {controls setting of autoerase flag if switched on, }
  55.                                                                         {this procedure will initialize the oldBounds var    }
  56.                 procedure SetUseBounds (TurnOn: Boolean);                {tells Draw and fDraw to collect bouding box data}
  57.                 procedure Draw;                                            {recalcs if neccessary, erases old image if auto- }
  58.                 override;                                                        {erase on, redraws all objects lines                     }
  59.                 procedure fDraw;                                            {like Draw but it collects data prior to drawing }
  60.                                                                         {thus making the actual drawing process a bit  }
  61.                                                                         {faster but the whole call is slower than Draw }
  62.                 procedure Erase;                                            {erase image of myself. this calcs and uses bounds}
  63.             end;
  64.  
  65. {Global Procedures for GrafSys}
  66.     procedure InitGrafSys;
  67.     procedure ArithmeticClip (var startV, endV: Point3DEntry; var skipThis, clippedThis: boolean; var sx, sy, ex, ey: integer);                                                                        {arithmetically clips a line that connects startV,endV }
  68.                                                                         {if it intersects the Z=0 plane. If it is completely behind }
  69.                                                                         {the Z=0 plane, skipThis is TRUE, if it intersects with }
  70.                                                                         {the plane, clippedThis becomes true and sx..ey contain}
  71.                                                                         {the new screen coordinates                                        }
  72.  
  73.  
  74. implementation
  75.  
  76.     type
  77.         screenBuffer = array[1..MaxLine] of record
  78.                 sx, sy: integer;
  79.                 ex, ey: integer;
  80.                 newLine: boolean;
  81.                 newLineColor: boolean;
  82.                 LineColor: RGBColor;
  83.             end;
  84.         screenBufPtr = ^screenBuffer;
  85.  
  86.  
  87.     var
  88.         theBlack: RGBColor;
  89.         lineBuffer: screenBufPtr;
  90.         center: Point; (* screen center in local coords of current 3d grafport *)
  91.         thed: real;
  92.         screenBufNumLines: integer; (* number of lines in scren buffer *)
  93.  
  94.     procedure InitGrafSys;
  95.     begin
  96.         InitMatrix; (* initialize the Matrix Package *)
  97.         lineBuffer := screenBufPtr(NewPtr(SIZEOF(screenBuffer)));
  98.         InitGrafSysScreen;
  99.         theBlack.red := 0;
  100.         theBlack.green := $0000;
  101.         theBlack.blue := 0;
  102.     end;
  103.  
  104. (* Clipping works the following way:  Eye orientation is looking in direction of positive z !!!!                               *)
  105. (*    - if both start and endpoint are behind the xy plane (have negative z-vals)  then the line is not shown at all. *)
  106. (*    - if both points have negative z-vals, the line is drawn entirely, no clipping required                                   *)
  107. (*    - otherwise the line is intersected with the xy plane and drawn from the point with positive z value to the  *)
  108. (*       intersection point                                                                                                                                    *)
  109.  
  110. (* new clipping algorithm :                                                                                                     *)
  111. (* first get start and endpoint                                                                                                 *)
  112. (* clipping only required if on opposite sides of the projection screen                                       *)
  113. (* if on opposite sides then we have to clip. the point to clip is always the endpoint of line, so   *)
  114. (*     we have to switch the two points if the endpoint is on the POSITIVE (=legal) side of plane  *)
  115.  
  116. (* the vars have the folloving meaning :                 *)
  117. (* s    : vector -- startpoint                                   *)
  118. (* e    : vector -- endpoint                                     *)
  119. (* dir : vector -- direction                                    *)
  120. (* t    : real -- parameter to calculate intersection *)
  121. (* d    : vector -- Intersection Point                       *)
  122.  
  123.  
  124.     procedure ArithmeticClip (var startV, endV: Point3DEntry; var skipThis, clippedThis: boolean; var sx, sy, ex, ey: integer);
  125.  
  126.         type
  127.             realV = array[1..3] of real;
  128.  
  129.         var
  130.             xform, xform2: Matrix4;
  131.             thePoint, dir, d, dummyV: realV;
  132.             zbyd: Real;
  133.             lineCount: integer;
  134.             clipstart: boolean;
  135.             t: Real;
  136.             eyeSafetyDist: real;
  137.             s, e: realV;
  138.  
  139.     begin
  140.         skipThis := FALSE;
  141.         clippedthis := FALSE;
  142. {startV := theScrnObj^.Point[sp];}
  143. {endV := theScrnObj^.Point[ep];       (* now we have start & endpoint for clipping in 3D *)
  144.         GetVector4(startV.transformed, s[1], s[2], s[3]);
  145.         GetVector4(endV.transformed, e[1], e[2], e[3]);
  146.         if ((s[3] <= 0) and (e[3] <= 0)) or ((s[3] > 0) and (e[3] > 0)) then
  147.             begin
  148.                 if ((s[3] <= 0) and (e[3] <= 0)) then (* no line is drawn *)
  149.                     skipThis := TRUE
  150.                 else
  151.                     begin (* whole line can be drawn, transfer it to the line buffer *)
  152.                         sx := startV.screenx; (* perspective xform has been applied already *)
  153.                         sy := startV.screeny;
  154.                         ex := endV.screenx;
  155.                         ey := endV.screeny;
  156.                     end;
  157.             end
  158.         else (* we have to clip. will always clip endpoint *)
  159.             begin
  160.                 clippedThis := TRUE;
  161.                 if s[3] < 0 then (* we have to switch start and endpoint since endpoint is legal one *)
  162.                     begin
  163.                         dummyV := s;
  164.                         s := e;
  165.                         e := dummyV;
  166.                         sx := endV.screenx; (* these screen coords don't have to be *)
  167.                         sy := endV.screeny; (* recalculated *)
  168.                     end
  169.                 else
  170.                     begin
  171.                         sx := startV.screenX;
  172.                         sy := startV.screenY;
  173.                     end; (* no switch *)
  174.  
  175.                 dir[1] := e[1] - s[1]; (* now calc direction vector *)
  176.                 dir[2] := e[2] - s[2];
  177.                 dir[3] := e[3] - s[3];
  178.  
  179.                 t := (0 - s[3]) / dir[3]; (* calc parameter for intersection *)
  180.                 d[1] := s[1] + (t * dir[1]); (* calc intersection Point *)
  181.                 d[2] := s[2] + (t * dir[2]);
  182.                 d[3] := 0;
  183.  
  184. (* now we have to perspective-project the intersection point *)
  185.                 if current3Dport^.projection = perspective then
  186.                     begin
  187.                         zbyd := 1 / (d[3] / thed + 1);
  188.                         ex := Trunc((d[1] * zbyd)) + center.h; (* do perspective transformation *)
  189.                         ey := -Trunc((d[2] * zbyd)) + center.v;
  190.                     end
  191.                 else
  192.                     begin
  193.                         ex := Trunc(d[1]) + center.h; (* do parallel projection *)
  194.                         ey := -Trunc(d[2]) + center.v;
  195.                     end; (* parallel *)
  196.             end; (* else we have to clip *)
  197.  
  198.     end; (* arithmetic clip *)
  199.  
  200.  
  201.  
  202.  
  203.     procedure TSObject3D.Init;
  204.     begin
  205.         inherited Init;
  206.         if ErrorCode <> noErr then
  207.             Exit(Init);
  208.         numLines := 0;
  209.         SetRect(Bounds, 0, 0, 0, 0);
  210.         oldBounds := Bounds;
  211.         AutoErase := False;
  212.         UseBounds := FALSE;
  213.         Lines := LineBufPtr(NewPtr(SIZEOF(LineBufRec)));
  214.         if Lines = nil then
  215.             ErrorCode := cOutOfMem;
  216.     end;
  217.  
  218.     procedure TSObject3D.Reset;
  219.         override;
  220.     begin
  221.         inherited Reset;
  222.         AutoErase := FALSE;
  223.         UseBounds := False;
  224.     end;
  225.  
  226. {Clone: extend this procedure to also allocate a line buffer and copy all data from }
  227. {          the original                                                                        }
  228.  
  229.     function TSObject3D.Clone: TGenericObject;
  230.         override;
  231.  
  232.         var
  233.             theClone: TSObject3D;
  234.  
  235.     begin
  236.         theClone := TSObject3D(inherited Clone);
  237.         theClone.Lines := LineBufPtr(NewPtr(SIZEOF(LineBufRec)));
  238.         if theClone.Lines = nil then
  239.             theClone.ErrorCode := cOutOfMem;
  240.         theClone.Lines^ := self.Lines^; (* copy the whole structure *)
  241.         Clone := theClone;
  242.     end;
  243.  
  244.     procedure TSObject3D.Kill;
  245.         override;
  246.     begin
  247.         DisposPtr(Ptr(Lines));
  248.         inherited Kill;
  249.     end;
  250.  
  251.     procedure TSObject3D.BuildNewLines;    {should not be called from the outside}
  252.         var
  253.             index: integer;
  254.  
  255.     begin
  256.         index := 2; (* check all lines starting with line two *)
  257.         while index <= numLines do
  258.             begin
  259.                 if Lines^[index].fromP = Lines^[index - 1].toP then
  260.                     Lines^[index].newLine := False
  261.                 else
  262.                     Lines^[index].newline := TRUE;
  263.                 index := index + 1;
  264.             end;
  265.         if numLines > 0 then
  266.             Lines^[1].newLine := TRUE; (* first line always true *)
  267.     end;
  268.  
  269.     function TSObject3D.AddLine (fIndex, tIndex: longint): integer; {add line to objects database. returns line index or -1 }
  270.     begin
  271.         fIndex := fIndex - 1;
  272.         if (fIndex < 0) or (fIndex > numPoints) then
  273.             begin
  274.                 ErrorCode := cIllegalPointIndex;
  275.                 AddLine := -1;
  276.                 Exit(AddLine);
  277.             end;
  278.         tIndex := tIndex - 1; (* make f and t zero-based *)
  279.         if (tIndex < 0) or (tIndex > numPoints) then
  280.             begin
  281.                 ErrorCode := cIllegalPointIndex;
  282.                 AddLine := -1;
  283.                 Exit(AddLine);
  284.             end;
  285.  
  286.         if numLines < MaxLine then
  287.             begin
  288.                 numLines := numLines + 1;
  289.                 Lines^[numLines].fromP := fIndex;
  290.                 Lines^[numLines].toP := tIndex;
  291.                 Lines^[numlines].newLineColor := FALSE;
  292.                 if numLines > 1 then
  293.                     if Lines^[numLines].fromP = Lines^[numLines - 1].toP then
  294.                         Lines^[numLines].newLine := False
  295.                     else
  296.                         Lines^[numLines].newline := TRUE
  297.                 else (* numLines = 1 *)
  298.                     Lines^[numLines].newline := TRUE;
  299.                 AddLine := numLines;
  300.                 objChanged := TRUE;
  301.             end
  302.         else
  303.             begin
  304.                 ErrorCode := cTooManyLines;
  305.                 AddLine := -1;
  306.             end;
  307.     end;
  308.  
  309.     function TSObject3D.ChangeLineColor (LineIndex: longint; theColor: RGBColor): boolean;
  310.                                                                         {change the color from this line on for all following }
  311.                                                                         {until the next ChangeColor command                      }
  312.     begin
  313.         if LineIndex <= numLines then
  314.             begin
  315.                 Lines^[LineIndex].newLineColor := TRUE;
  316.                 Lines^[LineIndex].LineColor := theColor;
  317.                 ChangeLineColor := TRUE;
  318.             end
  319.         else
  320.             begin
  321.                 ErrorCode := cIllegalLineIndex;
  322.                 ChangeLineColor := FALSE;
  323.             end;
  324.     end;
  325.  
  326.     function TSObject3D.GetLineColor (LineIndex: longint; var theColor: RGBColor; var ChangeHere: boolean): Boolean;
  327.                                                                         {returns the currently active color of specified line}
  328.         var
  329.             index: longint;
  330.  
  331.     begin
  332.         GetLineColor := TRUE;
  333.         theColor.red := 0;
  334.         theColor.green := 0;
  335.         theColor.blue := 0;
  336.         if LineIndex <= numLines then
  337.             begin
  338.                 index := 1;
  339.                 while index <= LineIndex do (* walk down all lines and change line color if neccessary *)
  340.                     begin
  341.                         ChangeHere := Lines^[LineIndex].newLineColor;
  342.                         if ChangeHere then
  343.                             theColor := Lines^[LineIndex].LineColor;
  344.                         index := index + 1;
  345.                     end;
  346.             end
  347.         else
  348.             begin
  349.                 ErrorCode := cIllegalLineIndex;
  350.                 GetLineColor := FALSE;
  351.             end;
  352.     end;
  353.  
  354.  
  355.     function TSObject3D.KeepLineColor (LineIndex: longint): boolean;
  356.                                                                         {deletes change linecolor information. This line and }
  357.                                                                         {all following will have the same color as the pre-  }
  358.                                                                         {vious                                                      }
  359.     begin
  360.         if LineIndex <= numLines then
  361.             begin
  362.                 Lines^[LineIndex].newLineColor := FALSE;
  363.                 KeepLineColor := TRUE;
  364.             end
  365.         else
  366.             begin
  367.                 ErrorCode := cIllegalLineIndex;
  368.                 KeepLineColor := FALSE;
  369.             end;
  370.     end;
  371.  
  372.     function TSObject3D.ChangeLine (LineIndex, fIndex, tIndex: longint): boolean;    {change line description of line with index }
  373.                                                                                             {lineIndex. True if successful                }
  374.     begin
  375.         fIndex := fIndex - 1;
  376.         if (fIndex < 0) or (fIndex > numPoints) then
  377.             begin
  378.                 ErrorCode := cIllegalPointIndex;
  379.                 ChangeLine := FALSE;
  380.                 Exit(ChangeLine);
  381.             end;
  382.         tIndex := tIndex - 1; (* make f and t zero-based *)
  383.         if (tIndex < 0) or (tIndex > numPoints) then
  384.             begin
  385.                 ErrorCode := cIllegalPointIndex;
  386.                 ChangeLine := FALSE;
  387.                 Exit(ChangeLine);
  388.             end;
  389.  
  390.         if LineIndex <= numLines then
  391.             begin
  392.                 Lines^[LineIndex].fromP := fIndex;
  393.                 Lines^[LineIndex].toP := tIndex;
  394.                 if LineIndex > 1 then
  395.                     if Lines^[LineIndex].fromP = Lines^[LineIndex - 1].toP then
  396.                         Lines^[LineIndex].newLine := False
  397.                     else
  398.                         Lines^[LineIndex].newline := TRUE
  399.                 else (* LineIndex = 1 *)
  400.                     Lines^[LineIndex].newline := TRUE;
  401.                 ChangeLine := TRUE;
  402.                 objChanged := TRUE;
  403.             end
  404.         else
  405.             begin
  406.                 ErrorCode := cIllegalLineIndex;
  407.                 ChangeLine := FALSE;
  408.             end;
  409.     end;
  410.  
  411.     function TSObject3D.DeleteLine (LineIndex: integer): Boolean;    {delete whole line from model. True on success}
  412.         var
  413.             index: integer;
  414.  
  415.     begin
  416.         if (LineIndex > numLines) or (LineIndex < 0) then
  417.             begin
  418.                 ErrorCode := cIllegalLineIndex;
  419.                 DeleteLine := FALSE;
  420.                 Exit(DeleteLine);
  421.             end;
  422. (* now move all line descs from above down once *)
  423.         index := lineIndex;
  424.         while index < numLines - 1 do
  425.             begin
  426.                 Lines^[index] := Lines^[index + 1];
  427.                 index := index + 1;
  428.             end;
  429.  
  430. (* rebuild newline at the deleted spot *)
  431.         if LineIndex > 1 then
  432.             if Lines^[LineIndex].fromP = Lines^[LineIndex - 1].toP then
  433.                 Lines^[LineIndex].newLine := False
  434.             else
  435.                 Lines^[LineIndex].newline := TRUE
  436.         else (* LineIndex = 1 *)
  437.             Lines^[LineIndex].newline := TRUE;
  438.         numLines := numLines - 1;
  439.         objChanged := TRUE;
  440.         DeleteLine := TRUE;
  441.     end;
  442.  
  443.     procedure TSObject3D.GetLine (lineIndex: integer; var src, tgt: LongInt); {returns start and endpoint of line or -1,-1}
  444.     begin
  445.         if (LineIndex > numLines) or (LineIndex < 0) then
  446.             begin
  447.                 ErrorCode := cIllegalLineIndex;
  448.                 src := -1;
  449.                 tgt := -1;
  450.                 Exit(GetLine);
  451.             end;
  452.         src := Lines^[lineIndex].fromP + 1;
  453.         tgt := Lines^[lineIndex].toP + 1;
  454.     end;
  455.  
  456.     function TSObject3D.DeletePoint (index: longint): boolean;    {override inherited proc of this kind. This one checks}
  457.         override;                                                            {first if point is referenced to by a point. If so, it }
  458.                                                                         {returns false and doesn't delete the point            }
  459.         var
  460.             hasRef: boolean;
  461.             lineIndex: integer;
  462.  
  463.     begin
  464. (* look if a point is referenced by any of the lines *)
  465.         hasRef := FALSE;
  466.         lineIndex := 1;
  467.         while not hasRef and (lineIndex <= numLines) do
  468.             begin
  469.                 if Lines^[lineIndex].fromP = index then
  470.                     hasRef := TRUE;
  471.                 if Lines^[lineIndex].toP = index then
  472.                     hasRef := TRUE;
  473.                 lineIndex := lineIndex + 1;
  474.             end;
  475.         if not hasRef then
  476.             DeletePoint := inherited DeletePoint(index)
  477.         else
  478.             begin
  479.                 ErrorCode := cCantDeletePoint;
  480.                 DeletePoint := FALSE;
  481.             end;
  482.         objChanged := TRUE;
  483.         DeletePoint := TRUE;
  484.     end;
  485.  
  486.  
  487.  
  488.     procedure TSObject3D.SetAutoerase (TurnOn: Boolean);
  489.     begin
  490.         Autoerase := TurnOn;
  491.         if AutoErase then
  492.             CalcBounds;
  493.     end;
  494.  
  495.     procedure TSObject3D.SetUseBounds (TurnOn: Boolean);        {tells Draw and fDraw to collect bouding box data}
  496.     begin
  497.         UseBounds := TurnOn;
  498.     end;
  499.  
  500.  
  501.     procedure TSObject3D.CollectLineData; {internal use only. fill the screen vals from point definition into line array}
  502.  
  503.         var
  504.             index: integer;
  505.             lBufIndex: integer; (* index to the line number in linebuf. always <= numLines *)
  506.             BufIndex, bufOffset: integer;
  507.             tempS, tempE: Point3DEntry;
  508.             clippedLast: Boolean; (* if this is true, the next line must have NewLine set to true *)
  509.             newLine: boolean;
  510.             skipThis: boolean;
  511.             ClipMode: ClippingType;
  512.             startx, starty, startz: real;
  513.             endx, endy, endz: real;
  514.             sx, sy, ex, ey: integer;
  515.             ClippedThis: Boolean;
  516.  
  517.     begin
  518.         index := 1;
  519.         lBufIndex := 1;
  520.         skipThis := FALSE;
  521.         ClipMode := current3DPort^.clipping;
  522.         clippedLast := FALSE;
  523.         center := current3DPort^.center;
  524.         thed := current3DPort^.d;
  525.         while index <= numLines do
  526.             begin
  527.                 newLine := Lines^[index].newLine or clippedLast;
  528.                 GenIndex(Lines^[index].toP, BufIndex, bufOffset); (* this is executed anyways *)
  529.                 tempE := theBufs[BufIndex]^[bufOffset]; (* read entry *)
  530.                 GenIndex(Lines^[index].fromP, BufIndex, bufOffset);
  531.                 tempS := theBufs[BufIndex]^[bufOffset]; (* read entry *)
  532.                 LineBuffer^[lBufIndex].newLineColor := Lines^[index].newLineColor;
  533.                 LineBuffer^[lBufIndex].lineColor := Lines^[index].lineColor;
  534. (* do clipping *)
  535.  
  536.                 case clipMode of
  537.                     none: 
  538.                         begin (* do nothing, just copy *)
  539.                             LineBuffer^[lBufIndex].sx := tempS.screenx;
  540.                             LineBuffer^[lBufIndex].sy := tempS.screeny;
  541.                             LineBuffer^[lBufIndex].ex := tempE.screenx;
  542.                             LineBuffer^[lBufIndex].ey := tempE.screeny;
  543.                             LineBuffer^[lBufIndex].newLine := newLine;
  544.                             lBufIndex := lBufIndex + 1;
  545.                         end;
  546.  
  547.                     arithmetic: 
  548.                         begin
  549.                             ArithmeticClip(tempS, tempE, skipThis, clippedThis, sx, sy, ex, ey);
  550.                             if skipThis then
  551.                                 clippedLast := TRUE
  552.                             else
  553.                                 begin
  554.                                     LineBuffer^[lBufIndex].sx := sx; (* copy data to buffer *)
  555.                                     LineBuffer^[lBufIndex].sy := sy;
  556.                                     LineBuffer^[lBufIndex].ex := ex;
  557.                                     LineBuffer^[lBufIndex].ey := ey;
  558.                                     LineBuffer^[lBufIndex].newLine := newLine or clippedThis;
  559.                                     lBufIndex := lBufIndex + 1;
  560.                     (* if something was clipped we might have to update the bounds array     *)
  561.                     (* the point that didn't get included was always the endpoint that got         *)
  562.                     (* clipped to the projection plane                                                             *)
  563.                                     if newLine or clippedThis then
  564.                                         begin
  565.                                             if ex < Bounds.left then (* gather data for autoerase *)
  566.                                                 Bounds.left := ex - 1;
  567.                                             if ex > Bounds.right then
  568.                                                 Bounds.right := ex + 1;
  569.                                             if ey < Bounds.top then
  570.                                                 Bounds.top := ey - 1;
  571.                                             if ey > Bounds.bottom then
  572.                                                 Bounds.bottom := ey + 1;
  573.                                         end;
  574.                                     clippedLast := clippedThis;
  575.                                 end;
  576.                         end;
  577.  
  578.  
  579.                     fast: (* very simple clipping method : remove all lines that fall at least partwise off the screen *)
  580.                         begin
  581.                             clippedLast := FALSE;
  582.                             GetVector4(tempS.transformed, startx, starty, startz);
  583.                             GetVector4(tempE.transformed, endx, endy, endz);
  584.                             if (startz < 0) or (endz < 0) then
  585.                                 begin
  586.                                     clippedLast := TRUE; (* don't copy line *)
  587.                                 end
  588.                             else
  589.                                 begin
  590.                                     LineBuffer^[lBufIndex].sx := tempS.screenx;
  591.                                     LineBuffer^[lBufIndex].sy := tempS.screeny;
  592.                                     LineBuffer^[lBufIndex].ex := tempE.screenx;
  593.                                     LineBuffer^[lBufIndex].ey := tempE.screeny;
  594.                                     LineBuffer^[lBufIndex].newLine := newLine;
  595.                                     lBufIndex := lBufIndex + 1;
  596.                                     clippedLast := FALSE;
  597.                                 end;
  598.                         end;
  599.  
  600.                     otherwise
  601.                         DebugStr('Unknown clipping method. TSObject3D.CollectLineDat')
  602.                 end; (* case clipMode *)
  603.  
  604. (* end of clipping *)
  605.  
  606.                 index := index + 1;
  607.             end; (* while index *)
  608.         screenBufNumLines := lBufIndex - 1; (* store number of lines in screenBuf *)
  609.         insetRect(Bounds, -1, -1); (* just do it anyways *)
  610.     end;
  611.  
  612.  
  613.     procedure TSObject3D.Draw;
  614.         override;
  615.         var
  616.             index: integer;
  617.             BufIndex, bufOffset: integer;
  618.             temp, tempS, tempE: point3DEntry;
  619.             theColor: RGBColor;
  620.             skippedLast: Boolean;
  621.             needMoveTo: Boolean;
  622.             skipThis, clippedThis: boolean;
  623.             sx, sy, ex, ey: integer;
  624.             ClipMode: ClippingType;
  625.             startx, starty, startz: real;
  626.             endx, endy, endz: real;
  627.  
  628.     begin
  629. (* first, set the current color to black *)
  630.         RGBForeColor(theBlack);
  631.         if Autoerase or UseBounds then
  632.             begin
  633.                 Transform2(FALSE); (* calc transform (if neccessary), transfor and gather autoerase data as well *)
  634.                 if Autoerase then
  635.                     EraseRect(oldBounds); (* erase old image. Its rect was stored in oldRect *)
  636.             end
  637.         else
  638.             Transform(FALSE);
  639.  
  640.     (* now begin drawing all lines of the object *)
  641.         ClipMode := current3DPort^.clipping;
  642.         center := current3DPort^.center;
  643.         thed := current3DPort^.d;
  644.         skippedLast := false;
  645.         index := 1;
  646.         while index <= numLines do
  647.             begin
  648.  
  649.                 if Lines^[index].newLineColor then
  650.                     RGBForeColor(LineBuffer^[index].LineColor);
  651.                 needMoveTo := skippedLast or Lines^[index].newLine; (* test if we need to use MoveTo call *)
  652.                 skippedLast := False; (* reset for this round of clipping *)
  653.  
  654. (* new we calculate clipping *)
  655.  
  656.                 case clipMode of
  657.                     none: 
  658.                         begin (* do nothing, just draw *)
  659.                             if needMoveTo then (* do only if we have to do a moveTo *)
  660.                                 begin
  661.                                     GenIndex(Lines^[index].fromP, BufIndex, bufOffset);
  662.                                     temp := theBufs[BufIndex]^[bufOffset]; (* read entry *)
  663.                                     Lines^[index].hs := temp.screenx;
  664.                                     Lines^[index].vs := temp.screeny;
  665.                                     MoveTo(temp.screenx, temp.screeny);
  666.                                 end;
  667.                             GenIndex(Lines^[index].toP, BufIndex, bufOffset);
  668.                             temp := theBufs[BufIndex]^[bufOffset]; (* read entry *)
  669.                             Lines^[index].he := temp.screenx;
  670.                             Lines^[index].ve := temp.screeny;
  671.                             LineTo(temp.screenx, temp.screeny);
  672.                         end;
  673.  
  674.                     arithmetic: 
  675.                         begin
  676.                             GenIndex(Lines^[index].fromP, BufIndex, bufOffset);
  677.                             tempS := theBufs[BufIndex]^[bufOffset]; (* read entry *)
  678.                             GenIndex(Lines^[index].toP, BufIndex, bufOffset);
  679.                             tempE := theBufs[BufIndex]^[bufOffset]; (* read entry *)
  680.                             ArithmeticClip(tempS, tempE, skipThis, clippedThis, sx, sy, ex, ey);
  681.                             if skipThis then
  682.                                 skippedLast := TRUE
  683.                             else
  684.                                 begin
  685.                                     if clippedThis then (* do this only if point is drawn *)
  686.                                         begin
  687.                                             if ex < Bounds.left then     (* gather data for autoerase. only if clipped         *)
  688.                                                 Bounds.left := ex - 1;    (* the point that needs to be checked is always     *)
  689.                                             if ex > Bounds.right then    (* the endpoint (sx,sy)                            *)
  690.                                                 Bounds.right := ex + 1;
  691.                                             if ey < Bounds.top then
  692.                                                 Bounds.top := ey - 1;
  693.                                             if ey > Bounds.bottom then
  694.                                                 Bounds.bottom := ey + 1;
  695.                                         end;
  696.                                     if needMoveTo or clippedThis then (* we need move to *)
  697.                                         MoveTo(sx, sy);
  698.                                     LineTo(ex, ey); (* draw it *)
  699.                                     skippedLast := clippedThis; (* indicate we need a moveto *)
  700.                                 end;
  701.                         end;
  702.  
  703.  
  704.                     fast: (* very simple clipping method : remove all lines that fall at least partwise off the screen *)
  705.                         begin
  706.                             GenIndex(Lines^[index].fromP, BufIndex, bufOffset);
  707.                             tempS := theBufs[BufIndex]^[bufOffset]; (* read entry *)
  708.                             GenIndex(Lines^[index].toP, BufIndex, bufOffset);
  709.                             tempE := theBufs[BufIndex]^[bufOffset]; (* read entry *)
  710.                             GetVector4(tempS.transformed, startx, starty, startz);
  711.                             GetVector4(tempE.transformed, endx, endy, endz);
  712.                             if (startz < 0) or (endz < 0) then
  713.                                 begin
  714.                                     skippedLast := TRUE; (* don't copy line *)
  715.                                 end
  716.                             else
  717.                                 begin (* draw line *)
  718.                                     if needMoveTo then
  719.                                         begin
  720.                         {Lines^[index].hs := tempS.screenx;}
  721.                         {Lines^[index].vs := tempS.screeny;}
  722.                                             MoveTo(tempS.screenx, tempS.screeny);
  723.                                         end;
  724.  
  725.                     {Lines^[index].he := tempE.screenx;}
  726.                     {Lines^[index].ve := tempE.screeny;}
  727.                                     LineTo(tempE.screenx, tempE.screeny);
  728.                                     skippedLast := FALSE;
  729.                                 end;
  730.                         end;
  731.                     otherwise
  732.                         DebugStr('Unknown clipping method');
  733.                 end; (* case *)
  734.  
  735. (* end of clipping *)
  736.  
  737.                 index := index + 1;
  738.             end; (* while index *)
  739.         insetRect(Bounds, -1, -1);
  740.         hasChanged := FALSE;
  741.     end;
  742.  
  743.  
  744.     procedure TSObject3D.fDraw;
  745.         override;
  746.         var
  747.             index: integer;
  748.  
  749.     begin
  750. (* first, set the current color to black *)
  751.         RGBForeColor(theBlack);
  752.         if Autoerase or useBounds then
  753.             begin
  754.                 Transform2(FALSE); (* calc transform (if neccessary), transfor and gather autoerase data as well *)
  755.                                 (* transform2 will move bounds -> oldBounds for ersure of old image *)
  756.             end
  757.         else
  758.             Transform(FALSE);
  759.  
  760.     (* now begin drawing all lines of the object *)
  761.  
  762.         CollectLineData; (* pre-gather all line-data for faster drawing. This includes clipping *)
  763.         index := 1;
  764.  
  765.         if AutoErase then
  766.             EraseRect(oldBounds); (* erase old image. Its rect was stored in oldBounds *)
  767.  
  768.         while index <= screenBufNumLines do
  769.             begin
  770.                 if LineBuffer^[index].newLineColor then (* first check the selected color *)
  771.                     RGBForeColor(LineBuffer^[index].LineColor);
  772.                 if LineBuffer^[index].newLine then
  773.                     MoveTo(LineBuffer^[index].sx, LineBuffer^[index].sy);
  774.                 LineTo(LineBuffer^[index].ex, LineBuffer^[index].ey);
  775.                 index := index + 1;
  776.             end;
  777.  
  778.         hasChanged := FALSE;
  779.     end;
  780.  
  781.     procedure TSObject3D.Erase;
  782.     begin
  783.         self.CalcBounds;
  784.         EraseRect(oldBounds);
  785.     end;
  786.  
  787. end.